package com.cool.commonredis;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;

import java.io.IOException;
import java.util.List;

@ServletComponentScan
@SpringBootApplication
public class CommonRedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(CommonRedisApplication.class, args);
    }

    public static Integer count = 500;


    /**
     * 电商秒杀场景
     * <p>
     * 1.测试 redis事务冲突。需要提前设置redis值：  set sk:1001:qt 10
     * 2.解决redis事务冲突超卖问题，有2步骤，1换成连接池 2使用乐观锁
     * 3.使用乐观锁（修改版本号）会造成库存问题，即便有商品，也无法卖出
     * 4. 使用lua嵌入式语言来解决此问题 https://www.bilibili.com/video/BV1Rv41177Af?p=27&vd_source=3c5672a416ac165826a145344ec5d29f
     *
     * @param productId 产品id
     * @param uid       uid
     * @return {@link Boolean}
     */
    public static Boolean killProd(String uid, String productId) {

        // 获取用户id 和商品id，不为空
        if (productId == null || uid == null) {

            return false;
        }

        // 连接redis
        // 拼接 库存Key
        // 拼接 用户Key

        String kcKey = "sk:" + productId + ":qt";
        String userKey = "sk:" + productId + ":usr";

        // 方式一。使用Jedis对象
//        Jedis jedis = new Jedis("127.0.0.1", 6379);

        // 方式二 使用jedis连接池
        JedisPool jedisPoolUtil = JedisPoolUtil.getInstance();
        Jedis jedis = jedisPoolUtil.getResource();

        jedis.select(1);

        // 1. 解决超卖问题。监视库存
        jedis.watch(kcKey);

        // 判断库存是否null，不为null，则开始秒杀
        String kcNumber = jedis.get(kcKey);

        if (kcNumber == null) {
            System.out.println("秒杀没开始");
            jedis.close();
            return false;
        }

        // 判断用户是否秒杀成功，每人限定一次
        jedis.sismember(userKey, uid);
        // 判断库存是否<1,小于1，结束
        if (Integer.parseInt(kcNumber) <= 0) {
            System.out.println("秒杀结束了");
            jedis.close();
            return false;
        }

        // 2. 解决超卖问题。添加事务
        Transaction transaction = jedis.multi();
        transaction.decr(kcKey);
        transaction.sadd(userKey, uid);

        // 2. 解决超卖问题。执行事务
        List<Object> result = transaction.exec();
        if (result == null || result.size() == 0) {
            System.out.println("秒杀失败了");
            jedis.close();
            return false;
        }

//        //库存 -1
//        jedis.decr(kcKey);
//        // 秒杀用户添加到成功清单
//        jedis.sadd(userKey, uid);
        count--;
        System.out.println("秒杀一次成功" + count.toString());
        return true;
    }


    /**
     * 秒杀了脚本
     */
    static String secKillScript = "local userid=KEYS[1];\r\n" +
            "local prodid=KEYS[2];\r\n" +
            "local qtkey='sk:'..prodid..\":qt\";\r\n" +
            "local usersKey='sk:'..prodid..\":usr\";\r\n" +
            "local userExists=redis.call(\"sismember\",usersKey,userid);\r\n" +
            "if tonumber(userExists)==1 then \r\n" +
            "   return 2;\r\n" +
            "end\r\n" +
            "local num= redis.call(\"get\" ,qtkey);\r\n" +
            "if tonumber(num)<=0 then \r\n" +
            "   return 0;\r\n" +
            "else \r\n" +
            "   redis.call(\"decr\",qtkey);\r\n" +
            "   redis.call(\"sadd\",usersKey,userid);\r\n" +
            "end\r\n" +
            "return 1";


    static String secKillScript2 =
            "local userExists=redis.call(\"sismember\",\"{sk}:0101:usr\",userid);\r\n" +
                    " return 1";


    public static boolean doSecKill(String uid, String prodId) throws IOException {

        JedisPool jedispool = JedisPoolUtil.getInstance();
        Jedis jedis = jedispool.getResource();
        jedis.select(1);

        //String sha1=  .secKillScript;
        String sha1 = jedis.scriptLoad(secKillScript);
        Object result = jedis.evalsha(sha1, 2, uid, prodId);

        String reString = String.valueOf(result);
        if ("0".equals(reString)) {
            System.err.println("已抢空！！");
        } else if ("1".equals(reString)) {
            System.out.println("抢购成功！！！！");
        } else if ("2".equals(reString)) {
            System.err.println("该用户已抢过！！");
        } else {
            System.err.println("抢购异常！！");
        }
        jedis.close();
        return true;
    }

}
